﻿using System;
using System.Collections.Generic;
using System.Text;
using AdaptiveAgents.TeammateModels;

namespace AdaptiveAgents.Agents.Choosers
{
    /// <summary>
    /// Chooses next player according to PDP with optimal (true) values in equations variables
    /// </summary>
    class PDPOptimalNextPlayerChooser : MDPDiscoverNextPlayerChooser_old
    {
        //both arrays stores true values of competences and epsilons
        private double[] comp;
        private double[] eps;

        public PDPOptimalNextPlayerChooser(Agent agent)
            : base(agent)
        {
            agent.NextPlayerChooser = this;
        }

        public PDPOptimalNextPlayerChooser(Agent agent, double[] comp, double[] eps)
            : base(agent)
        {
            agent.NextPlayerChooser = this;
            this.comp = comp;
            this.eps = eps;
        }

        /// <summary>
        /// Chooses the next performer according to MDP with optimal (true) values in equations variables
        /// </summary>
        /// <param name="maxToConsider"></param>
        /// <returns>index of next performer</returns>
        public override int choose(int maxToConsider)
        {

            #region oldChoose
            /*
            if (_me.ObservationsSet.observations.Count < _me.ChangeStrategyPoint) //HACK: Observe before decide about the MDP
                return Generator.getNextInt(3);

            int agentS, agent0, agent1;
            int numOfAgents = 3;

            agentS = _me.ID;
            agent0 = (agentS + 1) % 3;
            agent1 = (agentS + 2) % 3;

            double epsS = _me.Epsilon;
            double compS = _me.Competence.Mean;
            double compSHat = _me.getTeammateModel(agentS).EstimateCompetence();

            //double[] data = ((AdaptiveTeammateModel)_me.getTeammateModel(agent0)).estimateEpsilonAndCometence(_me.getObservations().observations);

            double eps0 = eps[0];
            double comp0 = comp[0];
            double comp0Hat = _me.getTeammateModel(agent0).EstimateCompetence();

            //data = ((AdaptiveTeammateModel)_me.getTeammateModel(agent1)).estimateEpsilonAndCometence(_me.getObservations().observations);

            double eps1 = eps[1];
            double comp1 = comp[1];
            double comp1Hat = _me.getTeammateModel(agent1).EstimateCompetence();

            double p0to0 = (1 - eps0) * (comp0 >= comp1Hat && comp0 >= compSHat ? 1 : 0);
            double p1to1 = (1 - eps1) * (comp1 >= comp0Hat && comp1 >= compSHat ? 1 : 0);

            int explotation0to1 = comp1Hat >= comp0Hat && comp1Hat >= compSHat && comp1Hat >= comp0 ? 1 : 0;
            int explotation0toS = compSHat >= comp0Hat && compSHat >= comp1Hat && compSHat >= comp0 ? 1 : 0;
            int explotation1to0 = comp0Hat >= comp1Hat && comp0Hat >= compSHat && comp0Hat >= comp1 ? 1 : 0;
            int explotation1toS = compSHat >= comp1Hat && compSHat >= comp0Hat && compSHat >= comp1 ? 1 : 0;

            double p0to1 = calcProbabilty(eps0, numOfAgents, explotation0to1);
            double p0toS = calcProbabilty(eps0, numOfAgents, explotation0toS);
            double p1to0 = calcProbabilty(eps1, numOfAgents, explotation1to0);
            double p1toS = calcProbabilty(eps1, numOfAgents, explotation1toS);

            //double[] vector = new double[4];
            solver.addEquation(setVector(LAMBDA * p0to0 - 1, LAMBDA * p0to1, LAMBDA * p0toS, -comp0));
            solver.addEquation(setVector(LAMBDA * p1to0, LAMBDA * p1to1 - 1, LAMBDA * p1toS, -comp1));
            solver.addEquation(setVector(LAMBDA, 0, -1, -compS));

            double[] result = solver.solve();
            double valueAgentSto0 = result[2];
            solver.clear();

            solver.addEquation(setVector(LAMBDA * p0to0 - 1, LAMBDA * p0to1, LAMBDA * p0toS, -comp0));
            solver.addEquation(setVector(LAMBDA * p1to0, LAMBDA * p1to1 - 1, LAMBDA * p1toS, -comp1));
            solver.addEquation(setVector(0, LAMBDA, -1, -compS));

            result = solver.solve();
            double valueAgentSto1 = result[2];
            solver.clear();

            solver.addEquation(setVector(LAMBDA * p0to0 - 1, LAMBDA * p0to1, LAMBDA * p0toS, -comp0));
            solver.addEquation(setVector(LAMBDA * p1to0, LAMBDA * p1to1 - 1, LAMBDA * p1toS, -comp1));
            solver.addEquation(setVector(0, 0, 1 - LAMBDA, compS));

            result = solver.solve();
            double valueAgentStoS = result[2];
            solver.clear();

            int index = chooseMaxValue(valueAgentSto0, agent0, valueAgentSto1, agent1, valueAgentStoS, agentS);

            return index;*/
            #endregion

            #region newChoose
            int returnIndex = 0;        
            int agentS, agent0, agent1;
            int numOfAgents = 3;

            agentS = _me.ID;
            agent0 = (agentS + 1) % 3;
            agent1 = (agentS + 2) % 3;

            double epsS = _me.Epsilon;
            double compS = _me.Competence.Mean;
            double compSHat = _me.getTeammateModel(agentS).EstimateCompetence();            

            double eps0 = eps[0];
            double comp0 = comp[0];
            double comp0Hat = _me.getTeammateModel(agent0).EstimateCompetence();            

            double eps1 = eps[1];
            double comp1 = comp[1];
            double comp1Hat = _me.getTeammateModel(agent1).EstimateCompetence();

            Record rec = new Record(epsS, eps0, eps1, compSHat, comp0Hat, comp1Hat, 0, 0, 0);
            ProjectCheckingTool checkTool = new ProjectCheckingTool();
            double[] result = checkTool.solveRecord(rec);
            returnIndex = returnNextAgent(agentS, result[0], agent0, result[1], agent1, result[2]);

            return returnIndex;
            #endregion

        }

        private int returnNextAgent(int ag0, double val0, int ag1, double val1, int ag2, double val2)
        {
            if ((val0 < val2) && (val1 < val2))
            {
                return ag2;
            }
            else if ((val0 < val1) && (val2 < val1))
            {
                return ag1;
            }
            else
            {
                return ag0;
            }
        }
    }
}
